package com.scrcu.core.batch.biz;

import com.boarsoft.common.Util;
import com.scrcu.core.batch.dao.SqlSessionDao;
import com.scrcu.core.batch.entity.BatchInst;
import com.scrcu.core.batch.entity.BatchLock;
import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Component
public class BatchInstBizImpl extends SqlSessionDao implements BatchInstBiz {

	private final Logger log  = LoggerFactory.getLogger(BatchInstBizImpl.class);

    private final String namespace = "com.scrcu.core.batch.BatchInst.";
    @Autowired
    private BatchLockBiz batchLockBiz;

    public BatchInstBizImpl(SqlSession dao) {
        super(dao);
    }

    @SuppressWarnings("unchecked")
    @Override
    @Transactional(readOnly = true)
    public List<BatchInst> list(String catalog) {
        List<BatchInst> list = dao.selectList(namespace.concat("selectListByCatalog"), catalog);
        return list;
    }

    @SuppressWarnings("unchecked")
    @Override
    @Transactional(readOnly = true)
    public BatchInst getActiveLock(int timeout) {
        BatchInst batchInst = dao.selectOne(namespace.concat("selectRecentLock"));
        if (batchInst == null) {
            log.warn("No record found in batch_inst: {}", namespace.concat("selectRecentLock"));
            return null;
        }
        if (batchInst.getCurrentTime().getTime() - batchInst.getLockTime().getTime() <= timeout * 1000l) {
            return batchInst;
        }
        return null;
    }

    @Override
    @Transactional
    public void updateLastTime(String addr) {
        dao.update(namespace.concat("updateLastTime"),addr);
    }


    @Override
    @Transactional
    public boolean acquireLock(String addr, int timeout, BatchLock optLock) {
        // 锁定BatchLock：若失败，说明已有其他批量实例更新了BatchInst.lockTime，结束
        if (!batchLockBiz.optimisticLock(optLock, addr)) {
            return false;
        }
        /*
         * 通过BatchLock.version判断BatchInst.lockTime是否为最新 // 查询当前有效的锁（未超时的锁）
         * BatchInst activeLock = getActiveLock(timeout); // 检查：是否存在有效的锁 且
         * 锁不属于自己 if (activeLock != null && !addr.equals(addr)) return false;
         */
        // 更新LockTime
        dao.update(namespace.concat("updateTimes"),addr);

        return true;
    }

    @Override
    @Transactional
    public void lock(BatchInst batchInst) {
        // 锁定BatchLock，排除其他调度更新BatchInst.lockTime
        batchLockBiz.pessimisticLock(batchInst.getCatalog(), batchInst.getAddr());

        // sleep 1s
        // 因为可能出现：
        // 原主调度的lastLockTime与本次更新的新主调度的lastLockTime相同，造成，原主调度再次checkLock时锁依然属于自己并再次启动
        // 进程休眠1秒，用来保证新主调度的lastLockTime必定为最大
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            throw new RuntimeException("Current thread is interrupted", e);
        }

        // 更新LockTime
        dao.update(namespace.concat("updateTimes"),batchInst.getAddr());
    }

    @Override
    @Transactional(readOnly = true)
    public BatchInst get(String addr) {
        return dao.selectOne(namespace.concat("selectByAddr"), addr);
    }

    @Override
    @Transactional
    public Object save(BatchInst o) {
        if (Util.strIsEmpty(o.getAddr())) {
            throw new RuntimeException("addr cannot be null");
        } else {
            return dao.update(namespace.concat("updateSelective"),o);
        }
    }

    @Override
    @Transactional
    public void delete(String id) {
        dao.delete(namespace.concat("deleteByAddr"), id);
    }

    @Override
    @Transactional(readOnly = true)
    public List<BatchInst> list() {
        return dao.selectList(namespace.concat("selectAll"));
    }
}
